package org.example.conf.aop;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.example.annot.RedisCache;
import org.example.util.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.concurrent.TimeUnit;

@Component
@Aspect
@Slf4j
public class RedisCacheAspect {
    @Autowired
    RedisUtils redisUtils;

    @Pointcut("@annotation(org.example.annot.RedisCache)")
    public void point(){}

    @Around(value = "point()")
    public Object around(ProceedingJoinPoint point ) throws Throwable{
        //1.获取切入点所在目标对象
        Object targetObj =point.getTarget();
        System.out.println(targetObj.getClass().getName());
        // 2.获取切入点方法的名字
        String methodName = point.getSignature().getName();
        System.out.println("切入方法名字："+methodName);
        // 3. 获取方法上的注解
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        Type returnType = method.getGenericReturnType();
        RedisCache annotation = method.getAnnotation(RedisCache.class);
        String rediskey = annotation.rediskey();
        long timeout = annotation.timeout();
        TimeUnit timeUnit = annotation.timeUnit();
        Object[] args = point.getArgs();
        Object arg0="";
        if(args!= null && args.length>=1){
            arg0 = args[0];
        }
        ObjectUtil.isBasicType(arg0);
        rediskey = StrUtil.replace(rediskey,"#{0}",arg0.toString());
        log.info("rediskey {}",rediskey);
        Object object = redisUtils.get(rediskey);
        if(object!= null){
            log.info("rediskey {} value {}",rediskey,object);
            return JSON.parseObject(object.toString(),returnType);
        }
        Object proceed = point.proceed();

        if(proceed!= null){
            log.info("cache rediskey {}",rediskey);
            redisUtils.set(rediskey,JSON.toJSONString(proceed),timeout,timeUnit);
        }
        return proceed;
    }
}
